package com.andy.beef.app.room

import androidx.lifecycle.viewModelScope
import com.andy.module.bean.CodeBean
import com.andy.module.network.ApiResponse
import com.andy.module.util.choose.CodeChooseManager
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.tencent.mmkv.MMKV
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.andy.network.base.BaseViewModel
import me.hgj.jetpackmvvm.ext.util.loge


/**
 * @creator:LuoFan
 * @date:2022/6/28
 * @description: 基础请求enum数据的model
 */
abstract class BaseEnumModel<T> : BaseViewModel(), CodeChooseManager.CodeLoader {

    //默认缓存2个小时
    var cacheTime = 2 * 60 * 60 * 1000

    override fun getData(groupKey: String, success: ((list: List<CodeBean>) -> Unit)) {
        val lastCacheTime = MMKV.defaultMMKV().getLong(genSaveKey(), 0)
        if (System.currentTimeMillis() - lastCacheTime > cacheTime) {
            requestNetData(success, groupKey)
        } else {
            viewModelScope.launch {
                getList(success, groupKey)
            }
        }
    }

    private suspend fun getList(success: ((list: List<CodeBean>) -> Unit), groupKey: String) {
        withContext(Dispatchers.IO) {
            val dao = com.andy.beef.app.room.BeefRoomDatabase.getDatabase().getCodeDao()
            val list = dao.getListByGroup(groupKey)
            withContext(Dispatchers.Main) {
                success.invoke(list)
            }
        }
    }

    private fun requestNetData(success: ((list: List<CodeBean>) -> Unit), groupKey: String): Job {
        return viewModelScope.launch {
            runCatching {
                //请求体
                loadingValue.showDialog.value = "true"
                genRequest()
            }.onSuccess { response ->
                loadingValue.dismissDialog.value = true
                if (response.isSuccess()) {
                    response.getResponseData()?.let {
                        saveResultList(it)
                        getList(success, groupKey)
                    }
                }
            }.onFailure {
                ToastUtils.showShort(it.message)
                loadingValue.dismissDialog.value = true
                it.message?.loge()
                //打印错误栈信息
                LogUtils.e(it.message)
            }
        }
    }

    private suspend fun saveResultList(result: T) {
        withContext(Dispatchers.IO) {
            val dao = com.andy.beef.app.room.BeefRoomDatabase.getDatabase().getCodeDao()
            val cls = result!!::class.java
            val methodList = cls.declaredMethods
            val saveList = mutableListOf<CodeBean>()
            methodList.forEach { method ->
                if (method.returnType.name == "java.util.List") {
                    val list = method.invoke(result) as? List<CodeBean>
                    list?.forEach {
                        it.groupKey = genGroupKey(method.name)
                    }
                    list?.let {
                        saveList.addAll(it)
                    }
                }
            }
            dao.insertList(saveList)
            MMKV.defaultMMKV().putLong(genSaveKey(), System.currentTimeMillis())
        }
    }

    private fun genGroupKey(methodName: String): String {
        var index = 0
        if (methodName.startsWith("is")) {
            index = 2
        } else if (methodName.startsWith("get")) {
            index = 3
        }
        val firstLetter = methodName[index].lowercase()
        return firstLetter + methodName.substring(index + 1)
    }

    abstract suspend fun genRequest(): ApiResponse<T>

    abstract fun genSaveKey(): String

}